// ------------------------------ 单链表 --------------------------------------
// Node 类用来表示节点。
// LinkedList 类提供插入节点、删除节点等一些操作。
// 单向链表的八种常用操作：

// append(element)：尾部添加元素。
// insert(position, element)：特定位置插入一个新的项。
// removeAt(position)：特定位置移除一项。
// remove(element)：移除一项。
// indexOf(element)：返回元素在链表中的索引。如果链表中没有该元素则返回 -1。
// isEmpty()：如果链表中不包含任何元素，返回 true，如果链表长度大于 0，返回 false。
// size()：返回链表包含的元素个数，与数组的 length 属性类似。
// getHead()：返回链表的第一个元素。
// toString()：由于链表使用了 Node 类，就需要重写继承自 JavaScript 对象默认的 toString() 方法，让其只输出元素的值。
// print()：打印链表的所有元素。

class Node {
  constructor(element) {
    this.element = element;
    this.next = null;
  }
}

class LinkedList {
  constructor() {
    this.length = 0;
    this.header = null;
  }

  append(element) {
    const node = new Node(element);
    let currentNode;
    // 添加元素时 判断有没有元素，没有就是第一个
    if (this.header === null) {
      this.header = node;
    } else {
      currentNode = this.header;
      // 从header开始找，循环找到下一个
      while(currentNode.next) {
        currentNode = currentNode.next;
      }
      // 当找到最后一个的时候，next指向新的节点
      currentNode.next = node;
    }
    // 长度+1
    this.length++;
  }

  insert(position, element) {
    if (position < 0 && position > this.length) {
      console.log(position, this.length)
      return false;
    }
    const node = new Node(element);
    let index = 0;
    let currentNode = this.header;
    let preNode;
    if(position === 0) {
      this.header = node;
      node.next = currentNode;
    } else {
      while(index < position) {
        preNode = currentNode;
        currentNode = currentNode.next;
        index++;
      }
      preNode.next = node;
      node.next = currentNode;
    }
    this.length++;
    return true;
  }

  removeAt(position) {
    if ((position < 0 && position > this.length) || this.length === 0) {
      return false;
    }
    let currentNode = this.header;
    let index = 0;
    let preNode;

    if (position === 0) {
      this.header = currentNode.next;
    } else {
      while(index < position) {
        preNode = currentNode;
        currentNode = currentNode.next;
        index++;
      }
      preNode.next = currentNode.next;
    }
    this.length--;
    return true;
  }

  remove(element) {
    const index = this.indexOf(element);
    this.removeAt(index);
  }

  indexOf(element) {
    let currentNode = this.header;
    let index = 0;
    while(currentNode) {
      if (currentNode.element === element) {
        return index;
      }
      index++;
      currentNode = currentNode.next;
    }
    return -1;
  }

  isEmpty() {
    return this.length === 0;
  }

  size() {
    return this.length;
  }

  toString() {
    let currentNode = this.header;
    let string = '';
    while(currentNode) {
      string += ',' + currentNode.element;
      currentNode = currentNode.next;
    }
    return string.slice(1);
  }

  print() {
    console.log(this.header)
  }

  getHead() {
    return this.header;
  }

}
// test
const link = new LinkedList();
link.append(5);
link.append(7);
link.append(3);
link.remove(7);
link.removeAt(1)
link.insert(1, 4);
link.insert(1, 6);
console.log(link.toString());
link.print();